/**
 * 
 */
package jm.lib.common.db;

import java.util.ArrayList;
import java.util.List;

import jm.lib.util.StrUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <strong>NOTICE:</strong> must setPageSize() first before <code>setPageIndex()</code> 
 * in case you do not use <code>setStartIndex()</code>
 * 
 * @author JimingLiu
 * 
 */
public class SearchClause {
	private static final Log logger = LogFactory.getLog(SearchClause.class);

	private List<SearchCondition> conditions = new ArrayList<SearchCondition>(5);
    private List<Order> orders = new ArrayList<Order>(2);

	private int pageSize = 15;

	private int startIndex = -1;


	/**
	 * It will set <code>startIndex</code> by
	 * <code>(pIndex - 1) * pageSize</code> <strong>NOTICE:</strong> must set
	 * it after you set <code>pageSize</code>
	 * 
	 * @param pIndex
	 *            start from 1, if it < 1, nothing happen
	 */
	public void setPageIndex(int pIndex) {
		startIndex = (pIndex<1?0:(pIndex-1)) * pageSize;
	}


	public int getPageSize() {
		return pageSize;
	}

	/**
	 * 
	 * @param pageSize if < 1, it will be set as default value 15.
	 */
	public void setPageSize(int pageSize) {
		if (pageSize < 1)
			return;
		this.pageSize = pageSize;
	}

	public int getStartIndex() {
		return startIndex;
	}

	/**
	 * 
	 * @param startIndex start form 0
	 */
	public void setStartIndex(int startIndex) {
		this.startIndex = startIndex;
	}

	public void addSearchCondition(SearchCondition condition) {
		this.conditions.add(condition);
	}

    public void addOrder(Order order) {
        this.orders.add(order);
    }

	public String getOrderByPart() {
		StringBuilder sb = new StringBuilder();
		getOrderByPart(sb);
		return sb.toString();
	}

	private void getOrderByPart(StringBuilder sb) {
        boolean first = true;
        for(Order o: orders) {
            if(first) {
                sb.append(" ORDER BY ");
            } else {
                sb.append(", "); 
            }
            sb.append(o.toString());
            first = false;
        }
	}

	public String getLimitPart() {
		StringBuilder sb = new StringBuilder();
		getLimitPart(sb);
		return sb.toString();
	}

	private void getLimitPart(StringBuilder sb) {
		if (this.startIndex >= 0) {
			sb.append(" LIMIT ");
			if (startIndex > 0) {
				sb.append(startIndex).append(',');
			}
			sb.append(pageSize);
		}
	}

	public String getConditionPart() {
		StringBuilder sb = new StringBuilder();
		if (this.conditions.size() > 0) {
			int counter = 0;
			for (SearchCondition condition : this.conditions) {
				String conditionStr = condition.toString();
				if (StrUtil.isNotEmpty(conditionStr)) {
					if (counter++ > 0) {
						sb.append(" AND");
					}
					sb.append(' ').append(conditionStr);
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 
	 * Get full condion with <strong>WHERE, ORDER BY, DESC, LIMIT</strong>
	 * 
	 * @return
	 */
	public String getClause() {
		return toString(false, true, true);
	}

	/**
	 * 
	 * Get full condion with <strong>WHERE, ORDER BY, DESC</strong>
	 * 
	 * @return
	 */
	public String getClauseWithoutLimit() {
		return toString(false, false, true);
	}

	/**
	 * 
	 * Get full condion with <strong>WHERE</strong> only
	 * 
	 * @return
	 */
	public String getClauseForCount() {
		return toString(true, false, true);
	}

	public String toString() {
		return getClause();
	}

	private String toString(boolean forCount, boolean withLimit,
			boolean withWhere) {
		StringBuilder sb = new StringBuilder();

		String conditionPart = getConditionPart();
		if (StrUtil.isNotEmpty(conditionPart)) {
			if (withWhere) {
				sb.append(" WHERE");
			}
			sb.append(conditionPart);
		}

		if (!forCount) {
			getOrderByPart(sb);
			if (withLimit)
				getLimitPart(sb);
		}

		return sb.toString();

	}

}
